package com.hyk.learning.remoting.retry;

import com.github.rholder.retry.*;
import com.hyk.learning.common.enums.RpcResponseCodeEnum;
import com.hyk.learning.dto.RpcRequest;
import com.hyk.learning.dto.RpcResponse;
import com.hyk.learning.remoting.transport.RpcRequestTransport;
import com.hyk.learning.remoting.transport.netty.client.NettyRpcClient;
import com.hyk.learning.remoting.transport.socket.SocketRpcClient;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @className: guavaRetry
 * @author: hyk199710
 * @description: TODO
 * @date: 2024/9/3 0:21
 */
@Slf4j
public class guavaRetry {
    private RpcRequestTransport rpcRequestTransport;

    public Object sendServiceWithRetry(RpcRequest rpcRequest, RpcRequestTransport rpcRequestTransport) throws Throwable {
        this.rpcRequestTransport =  rpcRequestTransport;
        Retryer<Object> retryer = RetryerBuilder.<Object>newBuilder()
                .retryIfException()
                .retryIfResult(response -> {
                    Integer code = RpcResponseCodeEnum.SUCCESS.getCode();
                    if(rpcRequestTransport instanceof NettyRpcClient) {
                        try {
                            code = ((CompletableFuture<RpcResponse<Object>>) response).get().getCode();
                        } catch (InterruptedException | ExecutionException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    else if (rpcRequestTransport instanceof SocketRpcClient){
                        code = ((RpcResponse<Object>) response).getCode();

                    }
                    return Objects.equals(code, RpcResponseCodeEnum.SUCCESS.getCode());
                })
                .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("RetryListener called {} times.", attempt.getAttemptNumber());
                    }
                }).build();
        try{
            return retryer.call(() -> rpcRequestTransport.sendRpcRequest(rpcRequest));
        } catch (Exception e){
            log.error("RpcRetry failed. {}", e.getMessage());
        }
        return RpcResponse.fail(RpcResponseCodeEnum.FAIL);
    }
}
